package model.doe;

public class FocusatorInRing extends AbstractDoe {

	private double apertureRad;
	private double focalLenght;
	private double ringRad;
	private double wl;
	private double step;
	private boolean withLens;
	private double cos;
	private double f0;
	private double r0;
	private double rad1;
	private double k0;
	private double psi0;

	public FocusatorInRing(double apertureRad, double focalLenght,
			double ringRad, double wl, double angle, double step,
			boolean withLens) {
		this.apertureRad = apertureRad;
		this.focalLenght = focalLenght;
		this.ringRad = ringRad;
		this.wl = wl;
		this.step = step;
		this.withLens = withLens;
		this.cos = Math.cos(angle * Math.PI / 180);
		widthPointsNumber = (int) (2*apertureRad / step);
		heightPointsNumber = (int) (2*apertureRad / step);

		kolco_init(this.focalLenght, this.ringRad, this.wl / 1000,
				this.apertureRad);
	}

	public double calculate(double u, double v) {
		if (withLens) {
			return kolco21(u, v);
		} else {
			return kolco20(u, v);
		}
	}

	
	// ************ Parameter initialization *********************************
	private void kolco_init(double f, double r, double wl, double rad) {

		double min1, max1, res;
		this.psi0 = 0;
		this.f0 = f;
		this.r0 = r;
		this.rad1 = rad;
		this.k0 = 2 * Math.PI / wl;
		min1 = k0 * f;
		max1 = k0 * Math.sqrt(f0 * f0 + r0 * r0);
		res = k0 * Math.sqrt(f0 * f0 + (rad - r0) * (rad - r0));
		if (res > max1)
			max1 = res;

		if (withLens) {
			max1 = ax(ax(-kolco1(0, 0), -kolco1(0, rad)), -kolco1(rad, 0));

			max1 = ax(max1, -kolco1(0, r));

			max1 = ax(max1, -kolco1(r, 0));

			max1 = ax(max1, -kolco1(rad / 2, 0));

			max1 = ax(max1, -kolco1(0, rad / 2));

			max1 = ax(max1, -kolco1(rad, rad));

			min1 = an(an(-kolco1(0, 0), -kolco1(0, rad)), -kolco1(rad, 0));

			min1 = an(min1, -kolco1(0, r));

			min1 = an(min1, -kolco1(r, 0));

			min1 = an(min1, -kolco1(rad / 2, 0));

			min1 = an(min1, -kolco1(0, rad / 2));

			min1 = an(min1, -kolco1(rad, rad));

		}

		psi0 = max1;
		maximumValue = max1;
		minValue = min1;
		return;
	}

	// _________________________________________________________________________

	private double kolco1(double u, double v) {

		// *********** Phase function when focusator as addition to lens
		// ************

		double psi, r;

		r = Math.sqrt(u * u + v * v);

		// psi=psi0-k0*sqrt(f0*f0+(r-r0)*(r-r0))+k0*sqrt(f0*f0+r*r);

		psi = psi0 - (k0 / f0) * r0 * r;

		return psi;
	}

	// ___________________________________________________________________________

	private double kolco0(double u, double v) {

		// ********** Phase function when focusator contains lens function
		// ********

		double psi, r;

		r = Math.sqrt(u * u + v * v);

		psi = psi0 - k0 * Math.sqrt(f0 * f0 + (r - r0) * (r - r0));

		// psi=psi0-(k0/f0)*r0*r;

		return psi;
	}

	// ____________________________________________________________________________

	private double kolco21(double u, double v) {

		if (Math.sqrt(u * cos * u * cos + v * v) > rad1)
			return -10e6;

		return kolco1(cos * u, v);

	}

	// ____________________________________________________________________________

	private double kolco20(double u, double v) {

		if (Math.sqrt(u * cos * u * cos + v * v) > rad1)
			return -10e6;

		return kolco0(cos * u, v);

	}

	private double ax(double a, double b) {

		double m = a;

		if (b > a)
			m = b;
		return m;
	}

	// __________________________________________________________________________

	private double an(double a, double b) {

		double m = a;

		if (b < a)
			m = b;
		return m;
	}

	@Override
	public double run(int i, int j) {	
		if (Math.sqrt(step * j * step * j + step * i * step * i) <= apertureRad) {
		
		return calculate(step * i, step * j);
		}
		else {
			return 0;
		}
	}
}
